/**
 * Copyright (c) Software Institute of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.modeler.check;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;

import edu.pku.sei.modeler.check.StructuredError.ErrorType;
import edu.pku.sei.modeler.internal.MetaModelingProject;
import edu.pku.sei.modeler.model.core.MetaClass;
import edu.pku.sei.modeler.model.core.MetaGeneralization;
import edu.pku.sei.modeler.model.core.MetaModel;
import edu.pku.sei.modeler.model.core.MetaPackage;

/**
 * @author danny
 *
 */
public class CheckRelationships implements IWorkspaceRunnable {
	private Object host;
	private List<StructuredError> errors;

	public CheckRelationships(Object host) {
		this.host = host;
		errors = new ArrayList<StructuredError>();
	}
	
	private void check(Object host) {
		if(host instanceof MetaModelingProject) {
			check(((MetaModelingProject)host).getModel());
		}
		else if(host instanceof MetaModel) {
			List pkgs = ((MetaModel)host).getPackages();
			for(int i=0; i<pkgs.size(); i++) {
				check(pkgs.get(i));
			}
		}
		else if(host instanceof MetaPackage) {
			List elements = new ArrayList();
			elements = ((MetaPackage)host).getNamedElements();
			for(int i=0; i<elements.size(); i++) {
				check(elements.get(i));
			}
			List pkgs = ((MetaPackage)host).getSubPackages();
			for(int i=0; i<pkgs.size(); i++) {
				check(pkgs.get(i));
			}
		}
		else if(host instanceof MetaClass) {
			List<MetaClass> parents = new ArrayList<MetaClass>();
			parents.add((MetaClass)host);
			List<MetaClass> circle = checkCircle((MetaClass)host, parents);
			if(circle != null) {
				StructuredError error = new StructuredError();
				error.setErrorType(ErrorType.ERROR);
				error.setModelID(String.valueOf((MetaClass)host));
				error.setTitle("Generalization Circle");
				String desp = "Generalization Circle:"+((MetaClass)host).getName();
				for(int i=circle.size()-1; i>=0; i--) {
					desp += "->"+circle.get(i).getName();
				}
				error.setDescription(desp);
				errors.add(error);
			}
		}
	}
	private List<MetaClass> checkCircle(MetaClass cls, List<MetaClass> parents) {
		List generals = cls.getGenerals();
		for (int i = 0; i < generals.size(); i++) {
			MetaGeneralization generalization = (MetaGeneralization)generals.get(i);
			MetaClass parentClass = generalization.getGeneral();
			if(parents.contains(parentClass)) {
				List<MetaClass> result = new ArrayList<MetaClass>();
				result.add(parentClass);
				return result;
			}
			parents.add(parentClass);
			List<MetaClass> tmp = checkCircle(parentClass, parents);
			if(tmp != null) {
				tmp.add(cls);
				return tmp;
			}
			parents.remove(parentClass);
		}
		return null;
	}
	/* (non-Javadoc)
	 * @see org.eclipse.core.resources.IWorkspaceRunnable#run(org.eclipse.core.runtime.IProgressMonitor)
	 */
	public void run(IProgressMonitor monitor) throws CoreException {
		if(host == null)return;
		monitor.setTaskName("Checking relationships...");
		check(host);
		monitor.worked(1);
	}
	
	/**
	 * @return the errors
	 */
	public List<StructuredError> getErrors() {
		return errors;
	}

}
